package org.iweb.html.api;

import java.io.Serializable;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.UUID;

import org.iweb.html.impl.session.MainManager;

public abstract class AbstractHtmlElement implements HtmlElement,Serializable {

	private static final long serialVersionUID = 6139944882285013413L;
	private Map<String, String> attributes;
	private Map<String, String> style;
	private Map<String, AbstractHtmlElement> childs;

	private String internalId;
	private AbstractHtmlElement parent;
	private Text text;

	public final String START_OPEN_TAG="<";
	public final String END_OPEN_TAG=">";
	public final String START_CLOSE_TAG="</";
	public final String END_CLOSE_TAG=">";

	public AbstractHtmlElement(){
		attributes=new LinkedHashMap<String,String>();
		internalId=UUID.randomUUID().toString();
		internalId="a"+internalId;

		attributes.put("id", internalId);
	}

	public AbstractHtmlElement(String text){
		this();
		setText(text);
	}

	public String getTag(){
		return this.getClass().getName().replaceFirst(this.getClass().getPackage().getName()+".", "").toLowerCase();
	}

	public String getId() {
		//return attributes.get("id")==null?internalId:attributes.get("id");
		return attributes.get("id");
	}


	public void setId(String id) {
		attributes.put("id", id);
	}


	public String getClassStyle() {
		return attributes.get("class");
	}


	public AbstractHtmlElement setClassStyle(String style) {
		attributes.put("class", style);
		return this;
	}

	public String getStartHtml(){
		String result=START_OPEN_TAG+getTag();
		for(String attr: attributes.keySet()){
			result+=(" "+attr+"=\""+attributes.get(attr)+"\"");
		}

		result+=END_OPEN_TAG;
		return result;
	}

	public String getEndHtml(){
		return START_CLOSE_TAG+getTag()+END_CLOSE_TAG;
	}

	public AbstractHtmlElement getParent() {
		if(parent==null)
			parent=this;
		return parent;
	}

	public void setParent(AbstractHtmlElement parent) {
		this.parent = parent;
	}


	public String getText() {
		return text==null?null:text.getValue();
	}

	public AbstractHtmlElement setText(String text) {
		if(this.text==null)
			this.text=new Text(text);
		else{
			String oldId=this.text.getInternalId();
			this.text=new Text(text);
			this.text.setInternalId(oldId);
		}
		getChilds().put(""+this.text.getInternalId(),this.text);
		return this;
	}

	public AbstractHtmlElement addAttr(String name,String value){
		attributes.put(name, value);
		return this;
	}

	public AbstractHtmlElement removeAttr(String name) {
		attributes.remove(name);
		return this;
	}

	public AbstractHtmlElement append(AbstractHtmlElement child){
		if(child!=null){
			child.setParent(this);
			getChilds().put(child.getInternalId(),child);
		}
		return this;
	}

	public AbstractHtmlElement remove(AbstractHtmlElement child){
		if(child!=null){
			getChilds().remove(child.getInternalId());
		}
		return this;
	}

	public AbstractHtmlElement replace(AbstractHtmlElement src,AbstractHtmlElement dest){
		if(src!=null && dest!=null){
			getChilds().put(src.getInternalId(),dest);
		}
		return this;
	}

	public Map<String,AbstractHtmlElement> getChilds() {
		if(childs==null)
			childs=Collections.synchronizedMap(new LinkedHashMap<String,AbstractHtmlElement>());
		return childs;
	}

	public Map<String, String> getAttributes() {
		return attributes;
	}


	public void setAttributes(Map<String, String> attributes) {
		this.attributes = attributes;
	}


	@Override
	public String render() {
		return renderRic("", this);
	}

	protected String renderRic(String result,AbstractHtmlElement element){
		try{

			if(element.style!=null)
				element.attributes.put("style", element.getAllStyle());

			element.onBeforeRender(result);
			if(element.getChilds().size()==0){
				return element.getStartHtml()+element.getEndHtml();
			}

			result+=element.getStartHtml();

			for(String childId: element.getChilds().keySet()){
				result+=renderRic("", element.getChilds().get(childId));
			}

			return result+element.getEndHtml();
		}finally{
			element.onAfterRender(result);
		}
	}

	public void onAfterRender(String result) {
		// TODO Auto-generated method stub

	}


	public void onBeforeRender(String result) {
		// TODO Auto-generated method stub

	}

	public Map<String, String> getStyle() {
		return style;
	}

	public void setStyle(Map<String, String> style) {
		this.style = style;
	}

	public void setChilds(Map<String, AbstractHtmlElement> childs) {
		this.childs = childs;
	}

	class Text extends AbstractHtmlElement{

		private static final long serialVersionUID = -9094572744734062131L;
		private String value;

		public Text(String value) {
			this.value=value;
			removeAttr("id").removeAttr("class");
		}

		@Override
		public String getTag() {
			return "";
		}

		@Override
		public String getStartHtml() {
			return value;
		}

		@Override
		public String getEndHtml() {
			return "";
		}

		public String getValue(){
			return value;
		}

		public void setValue(String value){
			this.value=value;
		}

	}


	/* EVENTS*/
	public void load(String url){
		addScript(new JScript().setScript("$(\"#"+getId()+"\").load(\""+url+"\");"));
	}

	public void click(JFunction function){
		//Html.addScript(new JScript().on("click", "#"+getId(), function));
		addScript(new JScript().on("click", "#"+getId(), function));
	}

	public void hide(){
		addScript(new JScript().setScript("$(\"#"+getId()+"\").hide();"));
	}

	public void show() {
		addScript(new JScript().setScript("$(\"#"+getId()+"\").show();"));
	}

	public void addClass(String className) {
		//return new JFunction("$(\"#"+getId()+"\").addClass(\""+className+"\");");
		addScript(new JScript().setScript("$(\"#"+getId()+"\").addClass(\""+className+"\");"));
	}

	public void removeClass(String className) {
		//return new JFunction("$(\"#"+getId()+"\").removeClass(\""+className+"\");");
		addScript(new JScript().setScript("$(\"#"+getId()+"\").removeClass(\""+className+"\");"));
	}

	public void attr(String name,String value){
		//return new JFunction("$(\"#"+getId()+"\").attr(\""+name+"\",\""+value+"\");");
		addScript(new JScript().setScript("$(\"#"+getId()+"\").attr(\""+name+"\",\""+value+"\");"));
	}

	public void attr(String name){
		//return new JFunction("$(\"#"+getId()+"\").attr(\""+name+"\");");
		addScript(new JScript().setScript("$(\"#"+getId()+"\").attr(\""+name+"\");"));
	}


	public String getInternalId() {
		return internalId;
	}


	public void setInternalId(String internalId) {
		this.internalId = internalId;
		setId(internalId);
	}

	public void css(String property,String value) {
		if(style==null)
			style=new LinkedHashMap<String, String>();
		style.put(property, value);
	}


	public String css(String property) {
		if(style==null)
			style=new LinkedHashMap<String, String>();
		return style.get(property);
	}

	public String getAllStyle(){
		if(style==null)
			return null;
		String result="";
		for(String k: style.keySet()){
			result+=(k+" : "+style.get(k)+"; ");
		}
		return result;
	}


	public AbstractHtmlElement addScript(JScript... script){
		for(JScript js: script){
			//AppManager.getAppState().addScript(js);
			MainManager.getAppSession().getAppState().addScript(js);
		}
		return this;
	}

	public void onClick(Listener l){

		MainManager.getAppSession().getObserver().registerListener(this.getId(),l);

		//AppManager.getAppState()
		MainManager.getAppSession().getAppState().addScript(new JScript().on(
				"click",
				"#" + this.getId(),
				new JFunction()
						.setBodyFunction("function(e){e.preventDefault(); onClick('"+this.getId()+"');}")));
	}

}
